//
//  SNActivityIndicatorView.m
//  activityindicator
//
//  Created by Nova on 13-4-20.
//  Copyright (c) 2013年 SINA. All rights reserved.
//

#import "ActivityIndicatorView.h"
#import "UIColor+BaseFramework.h"

@interface ActivityIndicatorItem : UIView
{
    UIImageView    *imageView;
}

- (id)initWithImage:(UIImage *)image
     indicatorWidth:(CGFloat)indicatorWidth
    indicatorHeight:(CGFloat)indicatorHeight
    indicatorRadius:(CGFloat)indicatorRadius;

@end

// -----------------------------------------------------------------------------------------------

@implementation ActivityIndicatorItem

- (void)dealloc
{
}

- (id)initWithImage:(UIImage *)image
     indicatorWidth:(CGFloat)indicatorWidth
    indicatorHeight:(CGFloat)indicatorHeight
    indicatorRadius:(CGFloat)indicatorRadius
{
    self = [super initWithFrame:CGRectMake(0, 0, indicatorWidth, indicatorHeight*0.5+indicatorRadius)];
    if (self) {
        self.layer.shadowOffset = CGSizeMake(0, 2);
        self.layer.shadowRadius = 3.0;
        self.layer.shadowColor = [UIColor whiteColor].CGColor;
        self.layer.shadowOpacity = 1.0;
        self.layer.shouldRasterize = YES;
        self.layer.masksToBounds = YES;
        
        imageView = [[UIImageView alloc] initWithImage:[image stretchableImageWithLeftCapWidth:(NSInteger)(image.size.width*0.5) topCapHeight:(NSInteger)(image.size.height*0.5)]];
        imageView.frame = CGRectMake(0, 0, indicatorWidth, indicatorHeight);
        imageView.backgroundColor = [UIColor colorWithHex:0x1f1f1f];
        imageView.layer.shadowOffset = CGSizeMake(0, 2);
        imageView.layer.shadowRadius = 3.0;
        imageView.layer.shadowColor = [UIColor whiteColor].CGColor;
        imageView.layer.shadowOpacity = 1.0;
        imageView.layer.shouldRasterize = YES;
        imageView.layer.masksToBounds = YES;
        [self addSubview:imageView];
    }
    
    return self;
}

@end

// -----------------------------------------------------------------------------------------------

@interface ActivityIndicatorView ()

- (void)removeAnimations;
- (void)addAnimations;

- (void)reloadItems;
- (void)setupItems;
- (void)removeItemAnimations;

- (CGAffineTransform)transformForItem:(ActivityIndicatorItem *)item atIndex:(NSInteger)index;
- (CGRect)frameForItem:(ActivityIndicatorItem *)item atIndex:(NSInteger)index;

- (void)hideItemsWithNewDisplayCount:(NSInteger)newDisplayCount animated:(BOOL)animated;
- (void)showItemsWithNewDisplayCount:(NSInteger)newDisplayCount animated:(BOOL)animated;

@end

@implementation ActivityIndicatorView

@synthesize currentDisplayCount;
@synthesize indicatorCount;

@synthesize indicatorWidth;
@synthesize indicatorHeight;
@synthesize indicatorRadius;

@synthesize spinDuration;
@synthesize indicatorSpinDuration;

@synthesize indicatorImage;

- (void)dealloc
{
    indicators, indicators = nil;
    indicatorImage, indicatorImage = nil;

}

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code
        currentDisplayCount = 0;
        indicatorCount = 12;
        
        indicatorWidth = 2;
        indicatorHeight = 5;
        indicatorRadius = 10;
        
        spinDuration = 2;
        indicatorSpinDuration = 0.1;
        
        indicators = [[NSMutableArray alloc] initWithCapacity:indicatorCount];
        
        [self setupItems];
    }
    
    return self;
}

- (void)startAnimating
{
    if (self.currentDisplayCount < self.indicatorCount) {
        [self setCurrentDisplayCount:self.indicatorCount animated:NO];
    }
    
    [self addAnimations];
}

- (void)stopAnimating
{
    [self removeAnimations];
    
//    if (self.currentDisplayCount > 0) {
//        [self setCurrentDisplayCount:0 animated:YES];
//    }
}

- (void)setupItems
{
    for (int i = 0; i < indicatorCount; i++) {
        ActivityIndicatorItem *indicator = [[ActivityIndicatorItem alloc] initWithImage:indicatorImage indicatorWidth:indicatorWidth indicatorHeight:indicatorHeight indicatorRadius:indicatorRadius];
        indicator.layer.anchorPoint = CGPointMake(0.5, 1.0);
        if (i < self.currentDisplayCount) {
            indicator.hidden = NO;
            indicator.frame = [self frameForItem:indicator atIndex:i];
            indicator.transform = [self transformForItem:indicator atIndex:i];
        }
        else {
            indicator.hidden = YES;
            indicator.frame = [self frameForItem:indicator atIndex:MAX(0, self.currentDisplayCount-1)];
            indicator.transform = [self transformForItem:indicator atIndex:MAX(0, self.currentDisplayCount-1)];
        }
        [self addSubview:indicator];
        [indicators addObject:indicator];
    }
}

- (void)removeItemAnimations
{
    for (ActivityIndicatorItem *item in indicators) {
        [item.layer removeAllAnimations];
    }
}

- (void)reloadItems
{
    [indicators makeObjectsPerformSelector:@selector(removeFromSuperview)];
    [indicators removeAllObjects];
    
    [self setupItems];
}

- (void)reloadItems:(void (^)(void))propertyBlock
{
    if (propertyBlock) {
        propertyBlock();
    }
    
    [self reloadItems];
}

- (void)setCurrentDisplayCount:(NSInteger)newDisplayCount animated:(BOOL)animated
{
    if (newDisplayCount < self.currentDisplayCount) {
        [self hideItemsWithNewDisplayCount:MAX(0, newDisplayCount) animated:animated];
    }
    else if (newDisplayCount > self.currentDisplayCount) {
        [self showItemsWithNewDisplayCount:MIN(newDisplayCount, self.indicatorCount) animated:animated];
    }
}

- (void)removeAnimations
{
    [self.layer removeAllAnimations];
}

- (void)addAnimations
{
    CABasicAnimation* rotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
    rotationAnimation.fromValue = [NSNumber numberWithFloat:0];
    rotationAnimation.toValue = [NSNumber numberWithFloat:2*M_PI];
    rotationAnimation.duration = self.spinDuration;
    rotationAnimation.repeatCount = HUGE_VALF;
    rotationAnimation.removedOnCompletion = NO;
    [self.layer addAnimation:rotationAnimation forKey:@"rotation"];
}

- (CGAffineTransform)transformForItem:(ActivityIndicatorItem *)item atIndex:(NSInteger)index
{
    return CGAffineTransformMakeRotation(index*2*M_PI/self.indicatorCount);
}

- (CGRect)frameForItem:(ActivityIndicatorItem *)item atIndex:(NSInteger)index
{
    return CGRectMake(CGRectGetMidX(self.bounds)-self.indicatorWidth*0.5, CGRectGetMidY(self.bounds)-CGRectGetHeight(item.bounds), CGRectGetWidth(item.bounds), CGRectGetHeight(item.bounds));
}

- (void)hideItemsWithNewDisplayCount:(NSInteger)newDisplayCount animated:(BOOL)animated
{
    if (animated) {
            [self removeItemAnimations];
            
            NSUInteger beginIndex = MAX(0, self.currentDisplayCount-1);
            NSUInteger transformIndex = MAX(0, self.currentDisplayCount-2);
            
            [UIView animateWithDuration:self.indicatorSpinDuration delay:0.0 options:UIViewAnimationOptionBeginFromCurrentState|UIViewAnimationOptionCurveLinear animations:^{
                for (int i = 0; i < indicatorCount; i++) {
                    ActivityIndicatorItem *item = [indicators objectAtIndex:i];
                    if (i < beginIndex) {
                        item.transform = [self transformForItem:item atIndex:i];
                        item.hidden = NO;
                    }
                    else if (i == beginIndex) {
                        item.transform = [self transformForItem:item atIndex:transformIndex];
                    }
                    else {
                        item.transform = [self transformForItem:item atIndex:transformIndex];
                        item.hidden = YES;
                    }
                }
            } completion:^(BOOL finished) {
                if (finished) {
                    ActivityIndicatorItem *item = [indicators objectAtIndex:beginIndex];
                    item.hidden = YES;
                    if (self.currentDisplayCount > 0) {
                        self.currentDisplayCount--;
                        [self setCurrentDisplayCount:newDisplayCount animated:animated];
                    }
                }
            }];
    }
    else {
        [self removeItemAnimations];
        
        self.currentDisplayCount = newDisplayCount;
        NSUInteger beginIndex = self.currentDisplayCount;
        NSUInteger transformIndex = MAX(0, self.currentDisplayCount-1);
        
        for (int i = 0; i < indicatorCount; i++) {
            ActivityIndicatorItem *item = [indicators objectAtIndex:i];
            if (i < beginIndex) {
                item.transform = [self transformForItem:item atIndex:i];
                item.hidden = NO;
            }
            else {
                item.transform = [self transformForItem:item atIndex:transformIndex];
                item.hidden = YES;
            }
        }
    }
}

- (void)showItemsWithNewDisplayCount:(NSInteger)newDisplayCount animated:(BOOL)animated
{
    if (animated) {
        [self removeItemAnimations];
        
        NSUInteger beginIndex = MIN(self.currentDisplayCount, self.indicatorCount-1);
        NSUInteger transformIndex = MIN(self.currentDisplayCount, self.indicatorCount-1);
        
        [UIView animateWithDuration:self.indicatorSpinDuration delay:0.0 options:UIViewAnimationOptionBeginFromCurrentState|UIViewAnimationOptionCurveLinear animations:^{
            for (int i = 0; i < indicatorCount; i++) {
                ActivityIndicatorItem *item = [indicators objectAtIndex:i];
                if (i <= beginIndex) {
                    item.transform = [self transformForItem:item atIndex:i];
                    item.hidden = NO;
                }
                else {
                    item.transform = [self transformForItem:item atIndex:transformIndex];
                    item.hidden = YES;
                }
            }
        } completion:^(BOOL finished) {
            if (finished) {
                if (self.currentDisplayCount < self.indicatorCount) {
                    self.currentDisplayCount++;
                    [self setCurrentDisplayCount:newDisplayCount animated:animated];
                }
            }
        }];
    }
    else {
        [self removeItemAnimations];
        
        self.currentDisplayCount = newDisplayCount;
        NSUInteger beginIndex = self.currentDisplayCount-1;
        NSUInteger transformIndex = self.currentDisplayCount-1;
        
        for (int i = 0; i < indicatorCount; i++) {
            ActivityIndicatorItem *item = [indicators objectAtIndex:i];
            if (i <= beginIndex) {
                item.transform = [self transformForItem:item atIndex:i];
                item.hidden = NO;
            }
            else {
                item.transform = [self transformForItem:item atIndex:transformIndex];
                item.hidden = YES;
            }
        }
    }
}

/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
    // Drawing code
}
*/

@end
